package protocol

import (
	"encoding/binary"
	"fmt"

	"google.golang.org/protobuf/proto"
)

const (
	NetStartSign = 0x11111111 // 网络启动
	NetHeadSize  = 9          // 包头长度
)

type NetHead struct {
	Start  [4]byte // 魔数 0x11111111
	Type   uint8   // 协议类型 T_NET_HEAD_TYPE_PROTOBUF
	PkgLen uint32  // 包长度
}

// 协议数据交互方式
const (
	NetHeadTypeJSON     = 0x02 //json
	NetHeadTypeProtobuf = 0x03 //protobuf
)

// 协议类型
const (
	DCEvent  = 0x01 // 事件主动上报信息
	DCNotify = 0x02 // 主动推送信息下发
	DCCmdRsp = 0x03 // 回复命令
	//DCCmdReq = 0x04 // 命令下发
)

// 协议模式
const (
	DCSingle = 0x01 // 单个客户端
	DCAll    = 0x02 // 广播
)

// 服务器到客户端消息
const (
	STCRegister     = 0x1000 // 回复注册
	STCHeartbeat    = 0x1001 // 心跳
	CTSHeartbeatRsp = 0x1002 // 回复心跳
	STCLightShow    = 0x101  // 获取灯光显示
	STCLightWarn    = 0x102  // 获取灯光告警
	//STCMasterOnline = 0x112  // 主客户端上线/下线
)

// 客户端到服务器消息
const (
	CTSRegister     = 0x2000 // 通知注册
	CTSHeartbeat    = 0x2001 // 通知心跳
	STCHeartbeatRsp = 0x2002 // 回复心跳
	//CTSLightShow       = 0x201  // 回复灯光显示
	//CTSLightWarn       = 0x202  // 回复灯光告警
	//CTSMasterOnlineRsp = 0x212  // 主客户端上线/下线回复
)

// ParseNetHead 解析消息包头
func ParseNetHead(data []byte) (*NetHead, error) {
	if len(data) < NetHeadSize {
		return nil, fmt.Errorf("header too short (%d < %d)", len(data), NetHeadSize)
	}

	if binary.BigEndian.Uint32(data[:4]) != NetStartSign {
		return nil, fmt.Errorf("invalid magic number: %08x", binary.BigEndian.Uint32(data[:4]))
	}

	return &NetHead{
		Start:  [4]byte{data[0], data[1], data[2], data[3]},
		Type:   data[4],
		PkgLen: binary.BigEndian.Uint32(data[5:9]),
	}, nil
}

// CompileMsg 封包，添加包头到消息包前面
func CompileMsg(headType uint8, data []byte) []byte {
	// fmt.Printf("send data len:%d\n", uint32(len(data)))
	msglen := uint32(len(data)) + NetHeadSize

	result := make([]byte, msglen)
	headBuf := make([]byte, NetHeadSize)
	binary.BigEndian.PutUint32(headBuf[0:4], NetStartSign)
	headBuf[4] = headType
	binary.BigEndian.PutUint32(headBuf[5:9], msglen)

	// fmt.Printf("headBuf:0x%x\n", headBuf)
	// fmt.Printf("data:0x%x\n", data)
	copy(result, headBuf)
	copy(result[NetHeadSize:], data)
	return result
}

// ReplyMsg 拼接发送信息
func ReplyMsg(headType uint8, data string, respType int32, respProto int32, respExt int32) ([]byte, error) {
	msg := &ProtoCommMsg{
		MsgProto:    respProto,
		MsgType:     respType,
		MsgProtoExt: respExt,
		Data:        data,
	}
	// fmt.Printf("ProtoCommMsg :%v\n", msg)
	// fmt.Printf("headType :%v\n", headType)
	msgData, err := proto.Marshal(msg)
	if err != nil {
		return nil, err
	}
	// fmt.Printf("proto.Marshal :%v\n", msgData)
	return CompileMsg(headType, msgData), nil
}
